package com.cloud.cop.validation;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import org.springframework.beans.BeanUtils;
import org.springframework.core.io.support.PropertiesLoaderUtils;
import org.springframework.util.ClassUtils;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;

import com.cloud.cop.CopRequest;
import com.cloud.cop.CopServiceContext;

public class DefaultCopValidator implements CopValidator {

	//支持的版本
	private static Set<String> SUPPORT_VERSION = new HashSet<String>();
	//支持的格式
	private static Set<String> SUPPORT_FORMAT = new HashSet<String>();
	
	private SessionChecker sessionChecker;
	private AppSecretManager appSecretManager;
	
	static {
		SUPPORT_VERSION.add("1.0");
		SUPPORT_FORMAT.add("XML");
		SUPPORT_FORMAT.add("JSON");
	}
	
	private static Map<String,SubErrorType> INVALIDE_CONSTRAINT_SUBERROR_MAPPINGS = new LinkedHashMap<String,SubErrorType>();
	
	static {
		INVALIDE_CONSTRAINT_SUBERROR_MAPPINGS.put("typeMismatch", SubErrorType.ISV_PARAMETERS_MISMATCH);
		INVALIDE_CONSTRAINT_SUBERROR_MAPPINGS.put("NotNull", SubErrorType.ISV_MISSING_PARAMETER);
		INVALIDE_CONSTRAINT_SUBERROR_MAPPINGS.put("NotEmpty", SubErrorType.ISV_INVALID_PARAMETE);
		INVALIDE_CONSTRAINT_SUBERROR_MAPPINGS.put("Size", SubErrorType.ISV_INVALID_PARAMETE);
		INVALIDE_CONSTRAINT_SUBERROR_MAPPINGS.put("Range", SubErrorType.ISV_INVALID_PARAMETE);
		INVALIDE_CONSTRAINT_SUBERROR_MAPPINGS.put("Pattern", SubErrorType.ISV_INVALID_PARAMETE);
		INVALIDE_CONSTRAINT_SUBERROR_MAPPINGS.put("Min", SubErrorType.ISV_INVALID_PARAMETE);
		INVALIDE_CONSTRAINT_SUBERROR_MAPPINGS.put("Max", SubErrorType.ISV_INVALID_PARAMETE);
		INVALIDE_CONSTRAINT_SUBERROR_MAPPINGS.put("DecimalMin", SubErrorType.ISV_INVALID_PARAMETE);
		INVALIDE_CONSTRAINT_SUBERROR_MAPPINGS.put("DecimalMax", SubErrorType.ISV_INVALID_PARAMETE);
		INVALIDE_CONSTRAINT_SUBERROR_MAPPINGS.put("Digits", SubErrorType.ISV_INVALID_PARAMETE);
		INVALIDE_CONSTRAINT_SUBERROR_MAPPINGS.put("Past", SubErrorType.ISV_INVALID_PARAMETE);
		INVALIDE_CONSTRAINT_SUBERROR_MAPPINGS.put("Future", SubErrorType.ISV_INVALID_PARAMETE);
		INVALIDE_CONSTRAINT_SUBERROR_MAPPINGS.put("AssertFalse", SubErrorType.ISV_INVALID_PARAMETE);
	}
	
	public DefaultCopValidator(){
		init();
	}
	
	//初始化会话检查和应用签名检查
	public void init(){
			sessionChecker = new DefaultSessionChecker();
			appSecretManager = new FileBaseAppSecretManager();
	}
	
	public MainError validate(CopServiceContext copServiceContext) {
		
		//检查参数完整性
		CopRequest request = copServiceContext.getCopRequest();
		MainError mainError = checkCopRequest(request);
		
		//检查签名
		if(mainError==null)
		mainError = checkSign(copServiceContext);
		
		//检查会话的有效性
		if(mainError==null)
			mainError = checkSession(copServiceContext);
		
		//此处不是检查属性错误，属性错误在数据绑定的时候已经检测完成，该处只是将错误转换为COP平台错误格式
		if(mainError == null){
			if(mainError==null&&(copServiceContext.getAllErrors()!=null&&copServiceContext.getAllErrors().size()>0)){
				mainError = beanConstraintError(copServiceContext.getAllErrors(),copServiceContext.getLocale());
			}
		}
			
		
		return mainError;
	}
	
	public MainError checkSign(CopServiceContext context){
		//获得所有的参数名称
		List<String> parameterNames = new ArrayList<String>(context.getWebRequest().getParameterMap().keySet());
		parameterNames.removeAll(context.getCopServiceHandler().getIgnoreSignFieldNames());
		
		//获得所有的参数值
		HashMap<String,String> parameterSignValueMap = new HashMap<String,String>();
		for(String parameterName : parameterNames){
			parameterSignValueMap.put(parameterName, context.getWebRequest().getParameter(parameterName));
		}
		
		String secret = getAppSecret(context.getAppKey());
		if(secret==null)
			return MainErrors.getErrors(MainErrorType.INVALID_APP_KEY, context.getLocale());
		//签名
		String signValue = sign(parameterNames,parameterSignValueMap,getAppSecret(context.getAppKey()));

		//验证签名
//		System.out.println(signValue);
		
//		if(!signValue.equals(context.getWebRequest().getParameter("sign"))){
//			//根据错误码，返回错误值
//			return MainErrors.getErrors(MainErrorType.INVALID_SIGNATURE,context.getLocale());
//		}
		
		return null;
	}
	
	//获得签名值
	public String sign(List<String> parameterNames,Map<String,String> parameters,String secret){
		StringBuilder sb = new StringBuilder();
		Collections.sort(parameterNames);
		sb.append(secret);
		for(String name:parameterNames){
			sb.append(name).append(parameters.get(name));
		}
		sb.append(secret);
		return CodeSecretGenerator.getDigestSHA(sb.toString()).toUpperCase();
	}
	
	
	public String getAppSecret(String appKey){
		return appSecretManager.getSecret(appKey);
	}

	//检查会话
	public MainError checkSession(CopServiceContext context){
		MainError mainError = null;
		if(context.getCopServiceHandler().isNeedInSession()&&!isValidateSession(context.getSessionId())){
			mainError = MainErrors.getErrors(MainErrorType.INVALID_SESSION, context.getLocale());
		}
		return mainError;
	}
	
	public boolean isValidateSession(String sessionId){
		return sessionChecker.isValid(sessionId);
	}
	
	//检查请求是否合法
	public MainError checkCopRequest(CopRequest request){
		
		//对象为空
		if(request==null){
			return MainErrors.getErrors(MainErrorType.INVALID_ARGUMENTS, request.getLocale());
		}else {
			
			//APPKEY 为空
			if(request.getAppKey()==null||"".equals(request.getAppKey())){
				return MainErrors.getErrors(MainErrorType.INVALID_APP_KEY, request.getLocale());
			}
			
			//方法为空
			if(request.getMethod()==null){
				return MainErrors.getErrors(MainErrorType.INVALID_METHOD, request.getLocale());
			}
			
			//版本号为空
			if(request.getVersion()==null){
				return MainErrors.getErrors(MainErrorType.INVALID_VERSION, request.getLocale());
			}else if(!isValidateVersion(request.getVersion())){
				return MainErrors.getErrors(MainErrorType.UNSUPPORTED_VERSION, request.getLocale());
			}
			
			//format为空
			if(!isValidateFormat(request.getFormat())){
				return MainErrors.getErrors(MainErrorType.INVALID_FORMAT, request.getLocale());
			}
			
			//签名值为空
			if(request.getSign() == null){
				return MainErrors.getErrors(MainErrorType.MISSING_SIGNATURE, request.getLocale());
			}
		}
		
		return null;
	}
	
	//对字段的错误进行转换
	public MainError beanConstraintError(List<ObjectError> allErrors,Locale locale){
		//属性错误属于参数错误的子错误
		MainError mainError = MainErrors.getErrors(MainErrorType.INVALID_ARGUMENTS, locale);
		for(ObjectError objectError : allErrors){
			if(objectError instanceof FieldError){
				FieldError fieldError = (FieldError)objectError;
				if(INVALIDE_CONSTRAINT_SUBERROR_MAPPINGS.containsKey(fieldError.getCode())){
					SubErrorType subErrorType = INVALIDE_CONSTRAINT_SUBERROR_MAPPINGS.get(fieldError.getCode());
					String subErrorCode = null;
					switch(subErrorType){
					case ISV_MISSING_PARAMETER:
					case ISV_INVALID_PARAMETE:
						subErrorCode = SubErrors.getSubErrorCode(subErrorType, fieldError.getField());
						break;
					case ISV_PARAMETERS_MISMATCH:
						subErrorCode = SubErrors.getSubErrorCode(subErrorType, fieldError.getField(),fieldError.getRejectedValue());
						break;
					default :
						 subErrorCode = SubErrors.getSubErrorCode(subErrorType, fieldError.getField());
					}
					SubError subError = SubErrors.getSubError(subErrorCode, subErrorType.value(), locale, fieldError.getField(),fieldError.getRejectedValue());
					mainError.addSubError(subError);
				}else {
					//如果没有在支持的范围之内，则全部认为是无效参数
					String subErrorCode = SubErrors.getSubErrorCode(SubErrorType.ISV_INVALID_PARAMETE, fieldError.getField());
                    SubError subError = SubErrors.getSubError(subErrorCode, SubErrorType.ISV_INVALID_PARAMETE.value(), locale, fieldError.getField());
                    mainError.addSubError(subError);
				}
			}
		}
		
		return mainError;
	}
	
	boolean isValidateVersion(String version){
		return SUPPORT_VERSION.contains(version);
	}
	
	boolean isValidateFormat(String format){
		return SUPPORT_FORMAT.contains(format.toUpperCase());
	}
}
